home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / ODUtils / Sources / AltPoly.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-16  |  17.8 KB  |  884 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        AltPoly.cpp
  3.  
  4.     Contains:    OpenDoc polygon: optional C++ savvy classes
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     To Do:
  11.                   
  12.         Improve the equality tests for contours and polygons. See comments
  13.         in the two "operator==" methods for details.
  14.     
  15.     In Progress:
  16.         
  17. */
  18.  
  19.  
  20. #ifndef _ALTPOINT_
  21. #include "AltPoint.h"            // Use C++ savvy ODPoint and ODRect
  22. #endif
  23.  
  24. #ifndef _ALTPOLY_
  25. #include "AltPoly.h"
  26. #endif
  27.  
  28. #ifndef SOM_ODTransform_xh
  29. #include "Trnsform.xh"
  30. #endif
  31.  
  32. #ifndef _LINEOPS_
  33. #include "LineOps.h"
  34. #endif
  35.  
  36. #ifndef _ODMEMORY_
  37. #include "ODMemory.h"
  38. #endif
  39.  
  40. #ifndef _EXCEPT_
  41. #include "Except.h"
  42. #endif
  43.  
  44. #ifndef SOM_ODStorageUnit_xh
  45. #include "StorageU.xh"
  46. #endif
  47.  
  48. #ifndef _STDTYPES_
  49. #include "StdTypes.xh"
  50. #endif
  51.  
  52. #ifndef _EXCEPT_
  53. #include "Except.h"
  54. #endif
  55.  
  56. #ifndef _ODDEBUG_
  57. #include "ODDebug.h"
  58. #endif
  59.  
  60. #ifndef _STORUTIL_
  61. #include <StorUtil.h>
  62. #endif
  63.  
  64. #ifndef _STDTYPIO_
  65. #include <StdTypIO.h>
  66. #endif
  67.  
  68. #ifndef _UTILERRS_
  69. #include "UtilErrs.h"
  70. #endif
  71.  
  72. #ifdef _PLATFORM_MACINTOSH_
  73.     #ifndef __GXERRORS__
  74.     #include "GXErrors.h"
  75.     #endif
  76.     #ifndef __GXGRAPHICS__
  77.     #include "GXGraphics.h"
  78.     #endif
  79. #endif
  80.  
  81. #include <stddef.h>                    // Defines offsetof() macro
  82.  
  83. #ifndef _ODDEBUG_
  84. #include "ODDebug.h"
  85. #endif
  86.  
  87.  
  88. const ODSLong kMaxLong    = 0x7FFFFFFF;
  89.  
  90. #pragma segment ODShape
  91.  
  92. //==============================================================================
  93. // Destructos
  94. //==============================================================================
  95.  
  96.  
  97. ODTempPolygon::ODTempPolygon( ) :
  98.     Destructo()
  99. {
  100.     // This constructor doesn't do anything special, but if not declared it will
  101.     // be inlined at the call site, resulting in lots of extra code due to the
  102.     // multiple inheritance.
  103. }
  104.  
  105.  
  106. ODTempPolygon::~ODTempPolygon( )
  107. {
  108.     this->Clear();
  109. }
  110.  
  111.  
  112. ODTempPolygonPtr::ODTempPolygonPtr( )
  113.     :fPoly(kODNULL)
  114. {
  115. }
  116.  
  117.  
  118. ODTempPolygonPtr::ODTempPolygonPtr( ODPolygon *p )
  119.     :fPoly(p)
  120. {
  121. }
  122.  
  123.  
  124. ODTempPolygonPtr::~ODTempPolygonPtr( )
  125. {
  126.     delete fPoly;
  127.     fPoly = kODNULL;
  128. }
  129.  
  130.  
  131. TempGXShape::TempGXShape( )
  132.     :fShape(kODNULL)
  133. {
  134. }
  135.  
  136.  
  137. TempGXShape::TempGXShape( gxShape s )
  138.     :fShape(s)
  139. {
  140. }
  141.  
  142.  
  143. TempGXShape::~TempGXShape( )
  144. {
  145.     if( fShape ) {
  146.         GXDisposeShape(fShape);
  147.         fShape = kODNULL;
  148.     }
  149. }
  150.  
  151. //==============================================================================
  152. // QuickDraw GX Utilities
  153. //==============================================================================
  154.  
  155.  
  156. #pragma segment QDGXShape
  157.  
  158.  
  159. static void
  160. ClearGXError( )
  161. {
  162.     GXGetGraphicsError(kODNULL);
  163.     // GX error status is cleared after asking for errors.
  164. }
  165.  
  166.  
  167. static void
  168. ThrowIfGXError( )
  169. {
  170.     gxGraphicsError err = GXGetGraphicsError(kODNULL);    // Get latest graphics error
  171.     if( err )
  172.         THROW(err,"QuickDraw GX error");
  173. }
  174.  
  175.  
  176. static void
  177. ThrowIfFirstGXError( )
  178. {
  179.     gxGraphicsError err;
  180.     (void) GXGetGraphicsError(&err);            // Get first error, not last
  181.     if( err )
  182.         THROW(err,"QuickDraw GX error");
  183. }
  184.  
  185.  
  186. /******************************************************************************/
  187. //**    ALLOCATION
  188. /******************************************************************************/
  189.  
  190.  
  191. ODPolygon::ODPolygon( )
  192.     :_maximum(0),
  193.      _length(0),
  194.      _buf(kODNULL)
  195. {
  196. }
  197.  
  198.  
  199. #if ODDebug
  200. ODPolygon::~ODPolygon( )
  201. {
  202.     // To help catch double-deletes of ODPolygon structures!
  203.     _buf = (ODPolygonData*)0xDDDDDDDD;
  204.     _length = _maximum = 0xDDDDDDDD;
  205. }
  206. #endif
  207.  
  208.  
  209. void
  210. ODPolygon::Delete( )
  211. {
  212.     ODDisposePtr(_buf);
  213.     delete this;
  214. }
  215.  
  216.  
  217. void
  218. ODPolygon::Clear( )
  219. {
  220.     ODDisposePtr(_buf);
  221.     _buf = kODNULL;
  222.     _length = _maximum = 0;
  223. }
  224.  
  225.  
  226. static ODULong
  227. CalcDataSize( ODSLong nVertices )
  228. {
  229.     if( nVertices==0 )
  230.         return 0;
  231.     else
  232.         return offsetof(ODPolygonData,firstContour.vertex[nVertices]);
  233. }
  234.  
  235.  
  236. void
  237. ODPolygon::Realloc( ODULong dataSize )
  238. {
  239.     if( _buf!=kODNULL && dataSize>=_length && dataSize<=_maximum )
  240.         _length = dataSize;
  241.     else {
  242.         ODPtr newData;
  243.         if( dataSize!=0 )
  244.             newData = ODNewPtr(dataSize, kDefaultHeapID);
  245.         ODDisposePtr(_buf);
  246.         if( dataSize!=0 )
  247.             _buf = (ODPolygonData*)newData;
  248.         else
  249.             _buf = kODNULL;
  250.         _length = _maximum = dataSize;
  251.     }
  252. }
  253.  
  254.  
  255. void
  256. ODPolygon::SetData( const ODPolygonData *data )
  257. {
  258.     _length = sizeof(ODULong) * (1+data->nContours);
  259.     const ODContour *c = &data->firstContour;
  260.     for( ODULong i=data->nContours; i!=0; i-- ) {
  261.         _length += c->nVertices * sizeof(ODPoint);
  262.         c = c->NextContour();
  263.     }
  264.     
  265.     ODDisposePtr(_buf);
  266.     _buf = (ODPolygonData*)data;
  267.     _maximum = _length;
  268. }
  269.  
  270.  
  271. ODPolygon*
  272. ODPolygon::SetNVertices( ODSLong nVertices )
  273. {
  274.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  275.     
  276.     this->Realloc(CalcDataSize(nVertices));
  277.     if( nVertices>0 ) {
  278.         _buf->nContours = 1;
  279.         _buf->firstContour.nVertices = nVertices;
  280.     }
  281.     return this;
  282. }
  283.  
  284.  
  285. ODPolygon*
  286. ODPolygon::SetVertices( ODSLong nVertices, const ODPoint *vertices )
  287. {
  288.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  289.     ASSERT(vertices!=kODNULL,kODErrIllegalNullInput);
  290.     
  291.     this->SetNVertices(nVertices);
  292.     if( nVertices>0 )
  293.         ODBlockMove( (void *) vertices, _buf->firstContour.vertex, nVertices*sizeof(ODPoint) );
  294.     return this;
  295. }
  296.  
  297.  
  298. ODPolygon*
  299. ODPolygon::SetContours( ODSLong nContours, const ODSLong *contourVertices )
  300. {
  301.     ASSERT(nContours>=0,kODErrValueOutOfRange);
  302.     if( nContours==0 )
  303.         return this->SetNVertices(0);
  304.     else {
  305.         ASSERT(contourVertices!=kODNULL,kODErrIllegalNullInput);
  306.         ODULong totalVertices = 0;
  307.         ODSLong i;
  308.         for( i=nContours-1; i>=0; i-- )
  309.             totalVertices += contourVertices[i];
  310.         this->Realloc( offsetof(ODPolygonData,firstContour)
  311.                      + offsetof(ODContour,vertex[0]) * nContours
  312.                      + sizeof(ODPoint)*totalVertices );
  313.         _buf->nContours = nContours;
  314.         ODContour *cont = this->FirstContour();
  315.         for( i=0; i<nContours; i++ ) {
  316.             cont->nVertices = contourVertices[i];
  317.             cont = cont->NextContour();
  318.         }
  319.         return this;
  320.     }
  321. }
  322.  
  323.  
  324. ODPolygon*
  325. ODPolygon::SetRect( const ODRect &r )
  326. {
  327.     if( r.IsEmpty() )
  328.         return this->SetNVertices(0);
  329.     else {
  330.         this->SetNVertices(4);
  331.         _buf->firstContour.vertex[0] = r.TopLeft();
  332.         _buf->firstContour.vertex[1].Set(r.right,r.top);
  333.         _buf->firstContour.vertex[2] = r.BotRight();
  334.         _buf->firstContour.vertex[3].Set(r.left,r.bottom);
  335.     }
  336.     return this;
  337. }
  338.  
  339.  
  340. ODPolygon*
  341. ODPolygon::CopyFrom( const ODPolygon &poly )
  342. {
  343.     if( poly._buf != _buf ) {
  344.         ODULong size = poly.GetDataSize();
  345.         this->Realloc(size);
  346.         ODBlockMove(poly.GetData(),_buf,size);
  347.     }
  348.     return this;
  349. }
  350.  
  351.  
  352. ODPolygon*
  353. ODPolygon::MoveFrom( ODPolygon &poly )
  354. {
  355.     if( poly._buf != _buf ) {
  356.         ODDisposePtr(_buf);
  357.         _buf = poly._buf;
  358.         _length = poly._length;
  359.         _maximum = poly._maximum;
  360.     }
  361.     if( &poly._buf != &_buf ) {            // Don't clear poly if it's myself!
  362.         poly._buf = kODNULL;
  363.         poly._length = poly._maximum = 0;
  364.     }
  365.     return this;
  366. }
  367.  
  368.  
  369.  
  370. #ifdef _PLATFORM_MACINTOSH_
  371. #pragma segment ODGXShape
  372.  
  373. ODPolygon*
  374. ODPolygon::CopyFrom( gxShape shape )
  375. {
  376.     ClearGXError();
  377.     TempGXShape copiedShape = GXCopyToShape(kODNULL,shape);
  378.     GXPrimitiveShape(copiedShape);
  379.     GXSimplifyShape(copiedShape);
  380.     GXSetShapeType(copiedShape,gxPolygonType);
  381.     ThrowIfFirstGXError();
  382.     
  383.     ODULong size = GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, kODNULL);
  384.     ThrowIfGXError();
  385.     this->Realloc(size);
  386.     GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, (gxPolygons*)_buf);
  387.     ThrowIfGXError();
  388.     
  389.     return this;
  390. }
  391. #pragma segment ODShape
  392. #endif
  393.  
  394.  
  395. ODPolygon*
  396. ODPolygon::ReadFrom( Environment *ev, ODStorageUnit *su )
  397. {
  398.  
  399.     if( !su->Exists(ev,kODNULL,kODPolygon,kODPosUndefined) ) {
  400.         this->Clear();
  401.     } else {
  402.         ODPropertyName propName = su->GetProperty(ev);
  403.         ODGetPolygonProp(ev, su, propName, kODPolygon, this);
  404.         ODDisposePtr((ODPtr) propName);
  405.     }
  406.  
  407.     return this;
  408. }
  409.  
  410.  
  411. ODPolygon*
  412. ODPolygon::WriteTo( Environment *ev, ODStorageUnit *su )  const
  413. {
  414.     ODPropertyName propName = su->GetProperty(ev);
  415.     ODSetPolygonProp(ev, su, propName, kODPolygon, this);
  416.     ODDisposePtr((ODPtr) propName);
  417.     
  418.     return (ODPolygon*)this;
  419. }
  420.  
  421.  
  422. /******************************************************************************/
  423. //**    POLYGON STUFF
  424. /******************************************************************************/
  425.  
  426.  
  427. ODSLong
  428. ODPolygon::GetNContours( )  const
  429. {
  430.     return _length>0 ?_buf->nContours :0;
  431. }
  432.  
  433.  
  434. const ODContour*
  435. ODPolygon::FirstContour( )  const
  436. {
  437.     return _length>0 ?&_buf->firstContour :kODNULL;
  438. }
  439.  
  440.  
  441. ODContour*
  442. ODPolygon::FirstContour( )
  443. {
  444.     return _length>0 ?&_buf->firstContour :kODNULL;
  445. }
  446.  
  447.  
  448. ODPolygon*
  449. ODPolygon::Copy( ) const
  450. {
  451.     ODTempPolygonPtr poly = new ODPolygon;
  452.     poly->CopyFrom(*this);
  453.     return poly.DontDelete();
  454. }
  455.  
  456.  
  457. void
  458. ODPolygon::ComputeBoundingBox( ODRect *bbox ) const
  459. {
  460.     ASSERT(bbox!=kODNULL,kODErrIllegalNullInput);
  461.     
  462.     if( _buf==kODNULL || _buf->nContours <= 0 ) {
  463.         bbox->Clear();
  464.         return;
  465.     }
  466.     
  467.     // Start bbox out as maximally empty:
  468.     bbox->left    = bbox->top        =  kMaxLong;
  469.     bbox->right = bbox->bottom    = -kMaxLong;
  470.     
  471.     const ODContour *c = this->FirstContour();
  472.     for( ODSLong i=this->GetNContours(); i>0; i-- ) {
  473.         ODPoint *pt = (ODPoint*)c->vertex;
  474.         for( ODSLong v=c->nVertices; v>0; v--,pt++ ) {
  475.             if( pt->x < bbox->left )    bbox->left    = pt->x;
  476.             if( pt->x > bbox->right )    bbox->right    = pt->x;
  477.             if( pt->y < bbox->top )        bbox->top    = pt->y;
  478.             if( pt->y > bbox->bottom )    bbox->bottom= pt->y;
  479.         }
  480.         if( i>1 )
  481.             c = c->NextContour();
  482.     }
  483. }
  484.  
  485.  
  486. ODBoolean
  487. ODContour::operator== ( const ODContour &cont ) const
  488. {
  489.     /*    This test is complicated by the fact that the two contours might have the
  490.         same points, but out of phase. Therefore we have to compare the points
  491.         in sequence, once per possible phase difference.  */
  492.     
  493.     ODSLong nv = this->nVertices;
  494.     if( nv != cont.nVertices )
  495.         return kODFalse;
  496.     
  497.     for( ODSLong phase=0; phase<nv; phase++ ) {
  498.         const ODPoint *p0 = &this->vertex[0];
  499.         const ODPoint *p1 = &cont.vertex[phase];
  500.         ODSLong i;
  501.         for( i=nVertices; i>0; i-- ) {
  502.             if( i==phase )
  503.                 p1 = &cont.vertex[0];
  504.             if( ! (p0++)->ApproxEquals(*p1++) )        // Coords may differ very slightly
  505.                 break;
  506.         }
  507.         if( i==0 )
  508.             return kODTrue;
  509.     }
  510.     return kODFalse;
  511. }
  512.  
  513.  
  514. Boolean
  515. ODPolygon::operator== ( ODPolygon &poly ) const
  516. {
  517.     /*    This test is complicated by the fact that the two polygons may not have their
  518.         contours in the same order. Our approach is to step through my contours in
  519.         order, trying to match each to a unique contour in the target. To ensure
  520.         uniqueness, the sign of the nVertices field in a target contour is flipped
  521.         after it's matched.  */
  522.     
  523.     if( this->GetNContours() != poly.GetNContours() )
  524.         return kODFalse;
  525.     if( &poly == this )
  526.         return kODTrue;
  527.     
  528.     ODBoolean result = kODTrue;
  529.     const ODContour * c = this->FirstContour();
  530.     ODContour *pc;
  531.     
  532.     ODSLong i;
  533.     for( i=this->GetNContours(); i>0; i-- ) {
  534.         pc = poly.FirstContour();
  535.         ODSLong j;
  536.         for( j=poly.GetNContours(); j>0; j-- ) {
  537.             if( pc->nVertices>0 && *c==*pc ) {        // Compare contours!
  538.                 pc->nVertices = -pc->nVertices;        // Use sign bit as a flag (yech)
  539.                 break;
  540.             }
  541.             if( j>1 )
  542.                 pc = pc->NextContour();
  543.         }
  544.         if( j<=0 ) {
  545.             result = kODFalse;                    // No match for contour
  546.             break;
  547.         }
  548.  
  549.         if( i>1 )
  550.             c = c->NextContour();
  551.     }
  552.  
  553.     // Now that we know, clear all the sign bits:
  554.     pc = poly.FirstContour();
  555.     for( i=poly.GetNContours(); i>0; i-- ) {
  556.         if( pc->nVertices<0 )
  557.             pc->nVertices = -pc->nVertices;
  558.         pc = pc->NextContour();
  559.     }
  560.     return result;
  561. }
  562.  
  563.  
  564. Boolean
  565. ODPolygon::IsEmpty( ) const
  566. {
  567.     // FIX: This is not very smart. It will probably be necessary to compute the area
  568.     // of each contour...
  569.     
  570.     return _buf==kODNULL || _buf->nContours==0;
  571. }
  572.  
  573.  
  574. Boolean
  575. ODPolygon::IsRectangular( ) const
  576. {
  577.     return _buf==kODNULL || _buf->nContours==0 ||
  578.             (_buf->nContours==1  && _buf->firstContour.IsRectangular());
  579. }
  580.  
  581.  
  582. Boolean
  583. ODPolygon::AsRectangle( ODRect *r ) const
  584. {
  585.     if( _buf==kODNULL || _buf->nContours==0 ) {
  586.         r->Clear();
  587.         return kODTrue;
  588.     } else if( _buf->nContours==1 )
  589.         return _buf->firstContour.AsRectangle(r);
  590.     else
  591.         return kODFalse;
  592. }
  593.  
  594.  
  595. Boolean
  596. ODContour::IsRectangular( ) const
  597. {
  598.     if( nVertices != 4 )
  599.         return kODFalse;
  600.     else if( vertex[0].x == vertex[1].x )            // 1st edge is vertical
  601.         return vertex[1].y==vertex[2].y
  602.             && vertex[2].x==vertex[3].x
  603.             && vertex[3].y==vertex[0].y;
  604.     else if( vertex[0].y == vertex[1].y )            // 1st edge is horizontal
  605.         return vertex[1].x==vertex[2].x
  606.             && vertex[2].y==vertex[3].y
  607.             && vertex[3].x==vertex[0].x;
  608.     else
  609.         return kODFalse;
  610. }
  611.  
  612.  
  613. Boolean
  614. ODContour::AsRectangle( ODRect *r ) const
  615. {
  616.     ASSERT(r!=kODNULL,kODErrIllegalNullInput);
  617.     
  618.     if( this->IsRectangular() ) {
  619.         ODRect r2(vertex[0],vertex[2]);            // C'tor properly orders the coords
  620.         *r = r2;
  621.         return kODTrue;
  622.     } else
  623.         return kODFalse;
  624. }
  625.  
  626.  
  627. /******************************************************************************/
  628. //**    REGION CONVERSION
  629. /******************************************************************************/
  630.  
  631.  
  632. ODBoolean
  633. ODContour::HasExactRegion( ) const
  634. {
  635.     const ODPoint *b = &vertex[0];
  636.     for( ODSLong i=nVertices; i>=0; i-- ) {
  637.         const ODPoint *a = &vertex[i];
  638.         if( (a->x & 0xFFFF) || (a->y & 0xFFFF) )
  639.             return kODFalse;                        // Non-integer coordinates
  640.         if( a->x!=b->x && a->y!=b->y )
  641.             return kODFalse;                        // Diagonal line
  642.         b = a;
  643.     }
  644.     return kODTrue;
  645. }
  646.  
  647.  
  648. ODBoolean
  649. ODPolygon::HasExactRegion( ) const
  650. {
  651.     const ODContour *c = this->FirstContour();
  652.     for( long i=this->GetNContours(); i>0; i-- ) {
  653.         if( !c->HasExactRegion() )
  654.             return kODFalse;
  655.         if( i>1 )
  656.             c = c->NextContour();
  657.     }
  658.     return kODTrue;
  659. }
  660.  
  661.  
  662. #ifdef _PLATFORM_MACINTOSH_
  663. PolyHandle
  664. ODContour::AsQDPolygon( ) const
  665. {
  666.     ODSLong size = (sizeof(short)+sizeof(Rect)+sizeof(Point)) + nVertices*sizeof(Point);
  667.     if( size > 32767 )
  668.         THROW(kODErrShapeTooComplex);
  669.     PolyHandle p = (PolyHandle) ODNewHandle(size);
  670.     (**p).polySize = (short)size;
  671.     Rect &bbox = (**p).polyBBox;
  672.     SetRect(&bbox,32767,32767,-32767,-32767);
  673.     
  674.     const ODPoint *src = &vertex[0];
  675.     Point *dst = &(**p).polyPoints[0];
  676.     for( ODSLong i=nVertices; i>0; i-- ) {
  677.         *dst = src->AsQDPoint();
  678.         if( dst->h < bbox.left  )    bbox.left  = dst->h;
  679.         if( dst->v < bbox.top   )    bbox.top   = dst->v;
  680.         if( dst->h > bbox.right )    bbox.right = dst->h;
  681.         if( dst->v > bbox.bottom)    bbox.bottom= dst->v;
  682.         src++;
  683.         dst++;
  684.     }
  685.     *dst = vertex[0].AsQDPoint();    // QD makes us repeat the 1st pt at the end
  686.     
  687.     return p;
  688. }
  689. #endif
  690.  
  691.  
  692. #ifdef _PLATFORM_MACINTOSH_
  693. RgnHandle
  694. ODPolygon::AsQDRegion( ) const
  695. {
  696.     // NOTE: This method will not work properly for self-intersecting polygons!
  697.     // QuickDraw uses even-odd filling, while OpenDoc uses winding-number.
  698.     
  699.     if( !this->HasData() )
  700.         return ODNewRgn();
  701.  
  702.     GrafPtr port, myPort;
  703.  
  704.     // Make sure we have a real port to work with:
  705.     GetPort(&port);
  706.     if( FrontWindow() ) {
  707.         SetPort(FrontWindow());
  708.         myPort = kODNULL;
  709.     } else {
  710.         myPort = new GrafPort;
  711.         OpenPort(myPort);
  712.     }
  713.     
  714.     RgnHandle rgn = ODNewRgn();
  715.     
  716.     OpenRgn();
  717.     TRY{
  718.         PolyHandle poly;
  719.         const ODContour *cont = this->FirstContour();
  720.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  721.             poly = cont->AsQDPolygon();
  722.             FramePoly(poly);
  723.             KillPoly(poly);
  724.             cont = cont->NextContour();
  725.         }
  726.     }CATCH_ALL{
  727.         CloseRgn(rgn);
  728.         DisposeRgn(rgn);
  729.         SetPort(port);
  730.         if( myPort ) {
  731.             ClosePort(myPort);
  732.             delete myPort;
  733.         }
  734.         RERAISE;
  735.     }ENDTRY
  736.     
  737.     CloseRgn(rgn);
  738.     
  739.     SetPort(port);
  740.     if( myPort ) {
  741.         ClosePort(myPort);
  742.         delete myPort;
  743.     }
  744.     return rgn;
  745. }
  746. #endif
  747.  
  748.  
  749. #ifdef _PLATFORM_MACINTOSH_
  750. gxShape
  751. ODPolygon::AsGXShape( ) const
  752. {
  753.     gxShape shape;
  754.     if( this->HasData() ) {
  755.         shape = GXNewPolygons( (gxPolygons*)this->GetData() );
  756.         GXSetShapeFill(shape,gxWindingFill);
  757.     } else
  758.         shape = GXNewShape(gxEmptyType);
  759.     
  760.     ThrowIfFirstGXError();
  761.     return shape;
  762. }
  763. #endif
  764.  
  765.  
  766. void
  767. ODPolygon::Transform( Environment *ev, ODTransform *xform )
  768. {
  769.     if( this->HasData() ) {
  770.         ODContour *c = &_buf->firstContour;
  771.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  772.             ODPoint *pt = c->vertex;
  773.             for( ODSLong v=c->nVertices; v>0; v--, pt++ )
  774.                 xform->TransformPoint(ev,pt);
  775.             if( i>1 )
  776.                 c = c->NextContour();
  777.         }
  778.     }
  779. }
  780.  
  781.  
  782. /******************************************************************************/
  783. //**    CONTAINMENT TEST
  784. /******************************************************************************/
  785.  
  786.  
  787. //------------------------------------------------------------------------------
  788. // ODPolygon::Contains
  789. //
  790. // Does a polygon contain a point?
  791. // We determine this by drawing a ray from the point to the right towards
  792. // infinity, and finding the polygon edges that intersect this ray. For each
  793. // such edge, count it as 1 if its y value is increasing, -1 if decreasing.
  794. // The sum of these values is 0 if the point is outside the polygon.
  795. //------------------------------------------------------------------------------
  796.  
  797. ODSLong
  798. ODPolygon::Contains( ODPoint point ) const
  799. {
  800.     if( !this->HasData() )
  801.         return kODFalse;
  802.  
  803.     ODSLong count = 0;
  804.     const ODPoint *pp1, *pp2;
  805.     ODPoint p1, p2;
  806.     ODPoint ray = point;
  807.     
  808.     for( PolyEdgeIterator polyIter (this); polyIter.IsNotComplete(); polyIter.Next() ) {
  809.         polyIter.CurrentEdge(pp1,pp2);
  810.         p1 = *pp1;
  811.         p2 = *pp2;
  812.         
  813.         if( p1.y==p2.y ) {                                            // Horizontal line: ignore
  814.             if( p1.y==point.y && InRange(point.x, p1.x,p2.x) ) {    // unless point is on it
  815.                 return 0;
  816.             }
  817.         } else {
  818.             ray.x = Max(p1.x,p2.x);
  819.             ODPoint sect;
  820.             if( ray.x >= point.x )
  821.                 if( IntersectSegments(p1,p2, point,ray, §) ) {
  822.                     if( WithinEpsilon(point.x,sect.x) && WithinEpsilon(point.y,sect.y) ) {
  823.                         return 0;
  824.                     }
  825.                     if( p2.y > p1.y )
  826.                         count++;
  827.                     else
  828.                         count--;
  829.                 }
  830.         }
  831.     }
  832.     
  833.     return count;
  834. }
  835.  
  836.  
  837. /******************************************************************************/
  838. //**    POLYGON EDGE ITERATOR
  839. /******************************************************************************/
  840.  
  841.  
  842. PolyEdgeIterator::PolyEdgeIterator( const ODPolygon *poly )
  843.     :fPoly (poly)
  844. {
  845.     fCurContour = poly->FirstContour();
  846.     fCurContourIndex = 0;
  847.     fCurVertex = 0;
  848. }
  849.  
  850.  
  851. void
  852. PolyEdgeIterator::CurrentEdge( const ODPoint* &v1, const ODPoint* &v2 )
  853. {
  854.     v1 = &fCurContour->vertex[fCurVertex];
  855.     if( fCurVertex+1 < fCurContour->nVertices )
  856.         v2 = v1+1;
  857.     else
  858.         v2 = &fCurContour->vertex[0];
  859. }
  860.  
  861.  
  862. Boolean
  863. PolyEdgeIterator::Next( )
  864. {
  865.     if( !fCurContour )                                    // Was already finished
  866.         return false;
  867.     if( ++fCurVertex >= fCurContour->nVertices )        // Next vertex; if past contour:
  868.         if( ++fCurContourIndex >= fPoly->GetNContours() ) {        // Next contour; if past end:
  869.             fCurContour = kODNULL;
  870.             return false;                                        //...we're done.
  871.         } else {
  872.             fCurContour = fCurContour->NextContour();            // Else go to start of contour
  873.             fCurVertex = 0;
  874.         }
  875.     return kODTrue;
  876. }
  877.  
  878.  
  879. Boolean
  880. PolyEdgeIterator::IsNotComplete( )
  881. {
  882.     return fCurContour!=kODNULL;
  883. }
  884.